<!DOCTYPE html>
<html>
<head>
    <title>ONNX图片识别系统</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        :root {
            --primary: #4285f4;
            --success: #34a853;
            --warning: #fbbc05;
            --danger: #ea4335;
        }
        body {
            font-family: 'Segoe UI', system-ui, sans-serif;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f8f9fa;
            color: #333;
        }
        .card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.08);
        }
        .section-title {
            color: var(--primary);
            margin-top: 0;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        .btn {
            display: inline-block;
            padding: 10px 16px;
            border-radius: 4px;
            border: none;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s;
        }
        .btn-primary {
            background: var(--primary);
            color: white;
        }
        .btn-primary:hover {
            background: #3367d6;
        }
        .btn-outline {
            background: transparent;
            border: 1px solid #ddd;
        }
        .btn-outline:hover {
            background: #f0f0f0;
        }
        .file-input {
            display: none;
        }
        .drop-area {
            border: 2px dashed #ccc;
            border-radius: 8px;
            padding: 30px;
            text-align: center;
            margin: 20px 0;
            transition: all 0.3s;
        }
        .drop-area.active {
            border-color: var(--primary);
            background-color: #f0f7ff;
        }
        #preview {
            max-width: 100%;
            max-height: 300px;
            margin: 15px auto;
            display: none;
            border-radius: 4px;
        }
        .progress-container {
            margin: 20px 0;
        }
        .progress-bar {
            height: 20px;
            background: #e0e0e0;
            border-radius: 10px;
            overflow: hidden;
        }
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, var(--success), #8bc34a);
            width: 0%;
            transition: width 0.5s;
        }
        .result-item {
            padding: 12px;
            margin: 8px 0;
            border-radius: 6px;
            background: #f8f9fa;
            display: flex;
            justify-content: space-between;
        }
        .top-item {
            border-left: 4px solid var(--primary);
            background: #e8f0fe;
        }
        .model-status {
            padding: 10px;
            border-radius: 4px;
            margin-bottom: 15px;
        }
        .status-badge {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 12px;
            font-weight: bold;
        }
        .status-ready {
            background: #e6f4ea;
            color: var(--success);
        }
        .status-not-ready {
            background: #fce8e6;
            color: var(--danger);
        }
        .loading {
            display: none;
            text-align: center;
            padding: 20px;
        }
        .spinner {
            border: 4px solid rgba(0,0,0,0.1);
            border-radius: 50%;
            border-top: 4px solid var(--primary);
            width: 30px;
            height: 30px;
            animation: spin 1s linear infinite;
            margin: 0 auto 10px;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .file-path {
            margin-top: 8px;
            font-size: 13px;
            color: #666;
            word-break: break-all;
        }
        .error-message {
            color: var(--danger);
            margin-top: 10px;
            font-size: 14px;
        }
        @media (max-width: 768px) {
            .card {
                padding: 15px;
            }
            .btn {
                padding: 8px 12px;
                font-size: 14px;
            }
        }
    </style>
</head>
<body>
    <h1 style="text-align: center; color: var(--primary);">ONNX图片识别系统</h1>
    
    <div class="card">
        <h2 class="section-title">1. 选择模型</h2>
        
        <div class="model-status" id="modelStatus">
            <span class="status-badge status-not-ready">未加载模型</span>
            <div id="modelInfo" style="margin-top: 10px; display: none;">
                <div><strong>输入尺寸:</strong> <span id="inputShape">未知</span></div>
                <div><strong>标签数量:</strong> <span id="labelCount">0</span></div>
            </div>
        </div>
        
        <div style="display: flex; gap: 10px; margin-bottom: 15px;">
            <button class="btn btn-outline" onclick="document.getElementById('modelFile').click()">
                选择ONNX模型
            </button>
            <input type="file" id="modelFile" class="file-input" accept=".onnx">
            
            <button class="btn btn-outline" onclick="document.getElementById('labelFile').click()">
                选择标签文件
            </button>
            <input type="file" id="labelFile" class="file-input" accept=".txt,.json">
        </div>
        
        <div id="filePaths">
            <div id="modelPathDisplay" class="file-path">未选择模型文件</div>
            <div id="labelPathDisplay" class="file-path">未选择标签文件</div>
        </div>
        
        <button class="btn btn-primary" id="loadModelBtn" style="margin-top: 10px;" disabled>
            加载模型
        </button>
        <div id="modelError" class="error-message"></div>
    </div>
    
    <div class="card">
        <h2 class="section-title">2. 识别图片</h2>
        
        <div class="drop-area" id="dropArea">
            <input type="file" id="fileInput" class="file-input" accept="image/*">
            <button class="btn btn-primary" onclick="document.getElementById('fileInput').click()">
                选择图片
            </button>
            <p style="margin-top: 10px; color: #666;">或拖拽图片到此处</p>
            <img id="preview">
        </div>
        
        <div class="loading" id="loading">
            <div class="spinner"></div>
            <p>正在分析图片...</p>
        </div>
        
        <div id="resultSection" style="display: none;">
            <h3 style="margin-top: 0;">识别结果</h3>
            <div id="predictionResult" style="font-size: 18px; font-weight: bold;"></div>
            
            <div class="progress-container">
                <div class="progress-bar">
                    <div class="progress-fill" id="confidenceBar"></div>
                </div>
                <div style="display: flex; justify-content: space-between; margin-top: 5px;">
                    <span>置信度:</span>
                    <span id="confidenceText">0%</span>
                </div>
            </div>
            
            <h4>Top 3 可能性:</h4>
            <div id="top3Results"></div>
        </div>
    </div>

    <script>
        // 全局状态
        const state = {
            modelFile: null,
            labelFile: null,
            modelLoaded: false
        };

        // DOM元素
        const elements = {
            modelFileInput: document.getElementById('modelFile'),
            labelFileInput: document.getElementById('labelFile'),
            loadModelBtn: document.getElementById('loadModelBtn'),
            modelStatus: document.getElementById('modelStatus'),
            modelInfo: document.getElementById('modelInfo'),
            modelPathDisplay: document.getElementById('modelPathDisplay'),
            labelPathDisplay: document.getElementById('labelPathDisplay'),
            modelError: document.getElementById('modelError'),
            fileInput: document.getElementById('fileInput'),
            dropArea: document.getElementById('dropArea'),
            preview: document.getElementById('preview'),
            loading: document.getElementById('loading'),
            resultSection: document.getElementById('resultSection'),
            predictionResult: document.getElementById('predictionResult'),
            confidenceBar: document.getElementById('confidenceBar'),
            confidenceText: document.getElementById('confidenceText'),
            top3Results: document.getElementById('top3Results'),
            inputShape: document.getElementById('inputShape'),
            labelCount: document.getElementById('labelCount')
        };

        // 初始化事件监听
        function init() {
            // 模型文件选择
            elements.modelFileInput.addEventListener('change', (e) => {
                if (e.target.files.length > 0) {
                    state.modelFile = e.target.files[0];
                    elements.modelPathDisplay.textContent = state.modelFile.path || state.modelFile.name;
                    checkReadyToLoad();
                }
            });

            // 标签文件选择
            elements.labelFileInput.addEventListener('change', (e) => {
                if (e.target.files.length > 0) {
                    state.labelFile = e.target.files[0];
                    elements.labelPathDisplay.textContent = state.labelFile.path || state.labelFile.name;
                    checkReadyToLoad();
                }
            });

            // 加载模型按钮
            elements.loadModelBtn.addEventListener('click', loadModel);

            // 图片拖拽功能
            setupDragAndDrop();

            // 图片选择
            elements.fileInput.addEventListener('change', (e) => {
                if (e.target.files.length > 0) {
                    handleImageFile(e.target.files[0]);
                }
            });
        }

        // 检查是否可以加载模型
        function checkReadyToLoad() {
            elements.loadModelBtn.disabled = !(state.modelFile && state.labelFile);
        }

        // 加载模型
        function loadModel() {
            const formData = new FormData();
            formData.append('model_path', state.modelFile.path || state.modelFile.name);
            formData.append('label_path', state.labelFile.path || state.labelFile.name);

            elements.loadModelBtn.disabled = true;
            elements.loadModelBtn.textContent = '加载中...';
            elements.modelError.textContent = '';

            fetch('/', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    // 更新UI状态
                    state.modelLoaded = true;
                    elements.modelStatus.innerHTML = `
                        <span class="status-badge status-ready">模型已加载</span>
                    `;
                    elements.modelInfo.style.display = 'block';
                    // 这里可以添加获取模型输入形状和标签数量的逻辑
                    
                    // 保存最近使用的模型路径
                    saveLastModelConfig({
                        model_path: state.modelFile.path || state.modelFile.name,
                        label_path: state.labelFile.path || state.labelFile.name
                    });
                } else {
                    elements.modelError.textContent = data.message;
                }
            })
            .catch(error => {
                elements.modelError.textContent = '加载失败: ' + error.message;
            })
            .finally(() => {
                elements.loadModelBtn.disabled = false;
                elements.loadModelBtn.textContent = '加载模型';
            });
        }

        // 保存最近使用的模型配置
        function saveLastModelConfig(config) {
            fetch('/save_config', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(config)
            }).catch(console.error);
        }

        // 设置拖拽功能
        function setupDragAndDrop() {
            const dropArea = elements.dropArea;

            ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, preventDefaults, false);
            });

            ['dragenter', 'dragover'].forEach(eventName => {
                dropArea.addEventListener(eventName, highlight, false);
            });

            ['dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, unhighlight, false);
            });

            function preventDefaults(e) {
                e.preventDefault();
                e.stopPropagation();
            }

            function highlight() {
                dropArea.classList.add('active');
            }

            function unhighlight() {
                dropArea.classList.remove('active');
            }

            dropArea.addEventListener('drop', function(e) {
                const dt = e.dataTransfer;
                if (dt.files.length > 0 && dt.files[0].type.match('image.*')) {
                    handleImageFile(dt.files[0]);
                }
            });
        }

        // 处理图片文件
        function handleImageFile(file) {
            if (!state.modelLoaded) {
                alert('请先加载模型文件！');
                return;
            }

            // 显示预览
            const reader = new FileReader();
            reader.onload = function(e) {
                elements.preview.src = e.target.result;
                elements.preview.style.display = 'block';
                elements.resultSection.style.display = 'none';
                
                // 上传识别
                recognizeImage(file);
            };
            reader.readAsDataURL(file);
        }

        // 识别图片
        function recognizeImage(file) {
            elements.loading.style.display = 'block';
            
            const formData = new FormData();
            formData.append('file', file);

            fetch('/', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                if (data.error) {
                    throw new Error(data.error);
                }
                displayResults(data);
            })
            .catch(error => {
                alert('识别失败: ' + error.message);
            })
            .finally(() => {
                elements.loading.style.display = 'none';
            });
        }

        // 显示结果
        function displayResults(data) {
            elements.resultSection.style.display = 'block';
            elements.predictionResult.textContent = `预测结果: ${data.prediction}`;
            
            // 动画显示置信度
            animateConfidence(data.confidence);
            
            // 显示top3结果
            let top3Html = '';
            data.top3.forEach((item, index) => {
                top3Html += `
                    <div class="result-item ${index === 0 ? 'top-item' : ''}">
                        <span>${index + 1}. ${item.class}</span>
                        <span>${(item.score * 100).toFixed(2)}%</span>
                    </div>
                `;
            });
            elements.top3Results.innerHTML = top3Html;
        }

        // 置信度动画
        function animateConfidence(confidence) {
            const percent = Math.round(confidence * 100);
            let current = 0;
            
            const interval = setInterval(() => {
                if (current >= percent) {
                    clearInterval(interval);
                } else {
                    current++;
                    elements.confidenceBar.style.width = current + '%';
                    elements.confidenceText.textContent = current + '%';
                    
                    // 动态颜色
                    if (current < 50) {
                        elements.confidenceBar.style.background = 'linear-gradient(90deg, var(--danger), var(--warning))';
                    } else if (current < 80) {
                        elements.confidenceBar.style.background = 'linear-gradient(90deg, var(--warning), #ffeb3b)';
                    } else {
                        elements.confidenceBar.style.background = 'linear-gradient(90deg, #8bc34a, var(--success))';
                    }
                }
            }, 20);
        }

        // 初始化应用
        init();
    </script>
</body>
</html>